import java.io.*;
import java.security.AccessControlException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * ICSFileCreatorFinal class
 * 
 * ICSFileCreatorFinal is the class for creating .ics files using the user inputed data from the Applet GUI.
 */
public class ICSFileCreatorFinal {

	/**
	 * createFiles() method
	 * 
	 * Modifies user inputed data from the GUI into a format that can be written to a .ics file, creates a filename from the event name and 
	 * time stamp, sets the file path where the created .ics files will be located, adjusts the user inputed time to reflect the selected 
	 * time zone, calls the .ics file creation methods, and returns a file creation confirmation message or an error message.
	 * 
	 * @param String		name				the event name
	 * @param int			startHourTime		the event time's starting hour
	 * @param int			startMinuteTime		the event time's starting minute
	 * @param String		startAMPM			the event time's starting AM/PM
	 * @param int			endHourTime			the event time's ending hour
	 * @param int			endMinuteTime		the event time's ending minute
	 * @param String		endAMPM				the event time's ending AM/PM
	 * @param int			month				the start month of the event
	 * @param int			day					the start day of the event
	 * @param int			year				the start year of the event
	 * @param int			endMonth			the end month of the event
	 * @param int			endDay				the end day of the event
	 * @param int			endYear				the end year of the event
	 * @param String		description			the event description
	 * @param String		location			the event location
	 * @param String		timezone			the event time zone
	 * @param String		comment				the event comment
	 * @param String		resources			the event resources
	 * @param String		priorityStr			the event priority, inputs can be "High", "Low", or "None"
	 * 
	 * @return	The .ics file contents as a string or an error message
	 */
	public static String createFiles(String name, int month, int day, int year, int endMonth, int endDay, int endYear, int startHourTime, 
									int startMinuteTime, String startAMPM, int endHourTime, int endMinuteTime, String endAMPM, 
									String description, String location, String timezone, String comment, String resources, 
									String priorityStr, String filename) {
		
		String 		message		= ""; // the error message or file confirmation message
		Calendar	cal			= Calendar.getInstance(); // a calendar based on the current time
		DateFormat	hourFormat	= new SimpleDateFormat("hh"); // a DateFormat for the current hour 
		DateFormat	minFormat	= new SimpleDateFormat("mm"); // a DateFormat for the current minute
		DateFormat	secFormat	= new SimpleDateFormat("ss"); // a DateFormat for the current second
		
		int		priority		= 0; // int representation of the priority level
		int		todayDay		= cal.get(Calendar.DATE); // today's day
		int		todayMonth		= cal.get(Calendar.MONTH); // today's month
		int		todayYear		= cal.get(Calendar.YEAR); // today's year
		Date 	currentDate 	= new Date(); // today's date
		String	currentHour		= hourFormat.format(currentDate); // the current hour
		String	currentMin		= minFormat.format(currentDate); // the current minute
		String	currentSec		= secFormat.format(currentDate); // the current second
		String	tempFilename	= "temp.ics"; // the temporary .ics filename
		int		versionCount	= 0; // the number of versions for a particular file
		int		filenameLength	= 0; // filename length
		File 	icsFile; // the .ics file
		String	absPathWFile 	= ""; // the absolute path to the .ics file excluding the filename
		int		pathLength		= 0; // the length of the absPathWFile string
		String 	absPathWOFile	= ""; // the absolute path to the .ics file including the filename
		String	msGooglePath	= ""; // the absolute path to the MS Outlook and Google Calendar compatible .ics file
		File	msGoogleFile; // the MS Outlook and Google Calendar compatible .ics file
		File	msGoogleDir; // the directory that stores the MS Outlook and Google Calendar compatible .ics files
		String	iCalPath 		= ""; // the absolute path to the Apple iCal compatible .ics file
		File	iCalFile; // the Apple iCal compatible .ics file
		File	iCalDir; // the directory that stores the Apple iCal compatible .ics files
		
		// Set int representation of priority level
		if (priorityStr.equals("High")) {
			priority = 1;
		}
		else if (priorityStr.equals("Low")) {
			priority = 9;
		}
		else if (priorityStr.equals("None")) {
			priority = 0;
		}
		
		// Set today's month
		if (todayMonth < 12) {
			todayMonth = todayMonth + 1;
		}
		else if (todayMonth == 12) {
			todayMonth = 1;
		}
		
		// Append a "0" to the front of an hour that has only one digit 
		if (currentHour.length() == 1) {
			currentHour = "0" + currentHour;
		}
		
		// Append a "0" to the front of a minute that has only one digit
		if (currentMin.length() == 1) {
			currentMin = "0" + currentMin;
		}
		
		// Append a "0" to the front of a second that has only one digit
		if (currentSec.length() == 1) {
			currentSec = "0" + currentSec;
		}
		
		filenameLength = tempFilename.length();
		icsFile = new File(tempFilename);
		
		try {
			// Set the absolute path where the created .ics files will be stored
			absPathWFile 	= icsFile.getAbsolutePath();
			pathLength 		= absPathWFile.length();
			absPathWOFile 	= absPathWFile.substring(0, pathLength - filenameLength);
			
			// Set the path for the MS Outlook and Google Calendar compatible .ics files
			msGooglePath	= absPathWOFile + "MS_Outlook-Google_Calendar\\";
			msGoogleDir	= new File(msGooglePath);
			
			filename = validateFilename(msGooglePath, filename, versionCount);
			filename = filename + ".ics";
			
			msGoogleFile	= new File(msGooglePath + filename);
			
			// Set the path for the Apple iCal compatible .ics files
			iCalPath		= absPathWOFile + "Apple_iCal\\";
			iCalDir			= new File(iCalPath);
			iCalFile		= new File(iCalPath + filename);
			
			// Set the start and end times according to their applicable time zones
			if (timezone.equals("Hawaii Standard Time")) {
				startHourTime = startHourTime - 10;
				if (startHourTime <= 0) {
					startHourTime = 12 + startHourTime;
				}
				endHourTime = endHourTime - 10;
				if (endHourTime <= 0) {
					endHourTime = 12 + endHourTime;
				}
				timezone = "Hawaiian Standard Time";
			}
			else if (timezone.equals("Alaska Daylight Time")) {
				startHourTime = startHourTime - 8;
				if (startHourTime <= 0) {
					startHourTime = 12 + startHourTime;
				}
				endHourTime = endHourTime - 8;
				if (endHourTime <= 0) {
					endHourTime = 12 + endHourTime;
				}
				timezone = "Alaskan Standard Time";
			}
			else if (timezone.equals("Pacific Daylight Time")) {
				startHourTime = startHourTime - 7;
				if (startHourTime <= 0) {
					startHourTime = 12 + startHourTime;
				}
				endHourTime = endHourTime - 7;
				if (endHourTime <= 0) {
					endHourTime = 12 + endHourTime;
				}
				timezone = "Pacific Standard Time";
			}
			else if (timezone.equals("Mountain Daylight Time")) {
				startHourTime = startHourTime - 6;
				if (startHourTime <= 0) {
					startHourTime = 12 + startHourTime;
				}
				endHourTime = endHourTime - 6;
				if (endHourTime <= 0) {
					endHourTime = 12 + endHourTime;
				}
				timezone = "Mountain Standard Time";
			}
			else if (timezone.equals("Central Daylight Time")) {
				startHourTime = startHourTime - 5;
				if (startHourTime <= 0) {
					startHourTime = 12 + startHourTime;
				}
				endHourTime = endHourTime - 5;
				if (endHourTime <= 0) {
					endHourTime = 12 + endHourTime;
				}
				timezone = "Central Standard Time";
			}
			else if (timezone.equals("Eastern Daylight Time")) {
				startHourTime = startHourTime - 4;
				if (startHourTime <= 0) {
					startHourTime = 12 + startHourTime;
				}
				endHourTime = endHourTime - 4;
				if (endHourTime <= 0) {
					endHourTime = 12 + endHourTime;
				}
				timezone = "Eastern Standard Time";
			}
			
			// Set the start and end hour times to a 24 hour clock
			if (startAMPM.equals("PM") && startHourTime < 13) {
				startHourTime = startHourTime + 12;
			}
			if (endAMPM.equals("PM") && endHourTime < 13) {
				endHourTime = endHourTime + 12;
			}
			
			// Replace all commas in the following strings with "\\,"
			timezone = replaceCommas(timezone);
			description = replaceCommas(description);
			comment = replaceCommas(comment);
			resources = replaceCommas(resources);
			location = replaceCommas(location);
			name = replaceCommas(name);
			
			// Create MS Outlook and Google Calendar compatible .ics files
			message = createMSGoogle(name, month, day, year, endMonth, endDay, endYear, startHourTime, startMinuteTime, startAMPM, endHourTime, endMinuteTime, 
					endAMPM, description, location, timezone, comment, resources, priority, msGoogleDir, msGoogleFile, todayYear, 
					todayMonth, todayDay, currentHour, currentMin, currentSec);
			
			// Create Apple iCal compatible .ics files
			message = message + createICal(name, month, day, year, endMonth, endDay, endYear, startHourTime, startMinuteTime, startAMPM, endHourTime, endMinuteTime, 
					endAMPM, description, location, timezone, comment, resources, priority, iCalDir, iCalFile, todayYear, 
					todayMonth, todayDay, currentHour, currentMin, currentSec);
			return message;
		} catch (AccessControlException e) {
			message = "Unable to access the necessary file systems, please check your Java Security Policy.";
		}
		return message;
	}
	
	/**
	 * createMSGoogle() method
	 * 
	 * Creates a new .ics event file in a file format compatible with MS Outlook or Google Calendar, prints to the .ics file, returns
	 * an error message when an exception occurs or a file creation confirmation message. 
	 * 
	 * @param String		name				the event name
	 * @param int			startHourTime		the event time's starting hour
	 * @param int			startMinuteTime		the event time's starting minute
	 * @param String		startAMPM			the event time's starting AM/PM
	 * @param int			endHourTime			the event time's ending hour
	 * @param int			endMinuteTime		the event time's ending minute
	 * @param String		endAMPM				the event time's ending AM/PM
	 * @param int			month				the start month of the event
	 * @param int			day					the start day of the event
	 * @param int			year				the start year of the event
	 * @param int			endMonth			the end month of the event
	 * @param int			endDay				the end day of the event
	 * @param int			endYear				the end year of the event
	 * @param String		description			the event description
	 * @param String		location			the event location
	 * @param String		timezone			the event time zone
	 * @param String		comment				the event comment
	 * @param String		resources			the event resources
	 * @param String		priority			the priority of the event, no priority == 0, highest priority == 1, lowest priority == 9
	 * @param File			msGoogleDir			the path to the directory where all MS Outlook compatible or Google Calendar .ics files are stored
	 * @param File			msGoogleFile		the path and filename of an MS Outlook or Google Calendar compatible .ics file
	 * @param int			todayYear			today's year which is used to create a time stamp
	 * @param int			todayMonth			today's month which is used to create a time stamp
	 * @param int			todayDay			today's day which is used to create a time stamp
	 * @param String		currentHour			the current hour which is used to create a time stamp
	 * @param String		currentMin			the current minute which is used to create a time stamp
	 * @param String		currentSec			the current second which is used to create a time stamp
	 * 
	 * @return	The .ics file contents as a string or an error message
	 */
	public static String createMSGoogle(String name, int month, int day, int year, int endMonth, int endDay, int endYear, int startHourTime, 
								int startMinuteTime, String startAMPM, int endHourTime, int endMinuteTime, String endAMPM, 
								String description, String location, String timezone, String comment, String resources, int priority, 
								File msGoogleDir, File msGoogleFile, int todayYear, int todayMonth, int todayDay, 
								String currentHour, String currentMin, String currentSec) {
		
		PrintWriter 	msGooglePW		= null; // writes to a text-output stream for MS Outlook and Google Calendar compatible .ics files
		
		String			monthStr		= Integer.toString(month); // a string representation of the Start Month
		String			dayStr			= Integer.toString(day); // a string representation of the Start Day
		String			endMonthStr		= Integer.toString(endMonth); // a string representation of the End Month
		String			endDayStr		= Integer.toString(endDay); // a string representation of the End Day
		String			todayMonthStr	= Integer.toString(todayMonth); // a string representation of today's month
		String			todayDayStr		= Integer.toString(todayDay); // a string representation of today's day
		String			startHourStr	= Integer.toString(startHourTime); // a string representation of the Start Time Hour
		String			startMinStr		= Integer.toString(startMinuteTime); // a string representation of the Start Time Minute
		String			endHourStr		= Integer.toString(endHourTime); // a string representation of the End Time Hour
		String			endMinStr		= Integer.toString(endMinuteTime); // a string representation of the End Time Minute
		String			fileContent		= ""; // the .ics file content
		
		// Create the directory where MS Outlook and Google Calendar .ics files will be stored, if it doesn't exist
		if (!msGoogleDir.exists()) {
			msGoogleDir.mkdir();
		}
		
		// Create the MS Outlook and Google Calendar compatible .ics file and write to it
		try {
			msGoogleFile.createNewFile();
			
			try {
				msGooglePW = new PrintWriter(msGoogleFile);
				
				if (monthStr.length() == 1) {
					monthStr = "0" + monthStr;
				}
				
				if (dayStr.length() == 1) {
					dayStr = "0" + dayStr;
				}
				
				if (endMonthStr.length() == 1) {
					endMonthStr = "0" + endMonthStr;
				}
				
				if (endDayStr.length() == 1) {
					endDayStr = "0" + endDayStr;
				}
				
				if (todayMonthStr.length() == 1) {
					todayMonthStr = "0" + todayMonthStr;
				}
				
				if (todayDayStr.length() == 1) {
					todayDayStr = "0" + todayDayStr;
				}
				
				if (startHourStr.length() == 1) {
					startHourStr = "0" + startHourStr;
				}
				
				if (startMinStr.length() == 1) {
					startMinStr = "0" + startMinStr;
				}
				
				if (endHourStr.length() == 1) {
					endHourStr = "0" + endHourStr;
				}
				
				if (endMinStr.length() == 1) {
					endMinStr = "0" + endMinStr;
				}
				
				fileContent = "BEGIN:VCALENDAR\r\n" +
						"VERSION:2.0\r\n" +
						"CALSCALE:GREGORIAN\r\n" +
						"METHOD:PUBLISH\r\n" +
						"X-WR-TIMEZONE:" + timezone + "\r\n" +
						"BEGIN:VTIMEZONE\r\n" +
						"TZID:" + timezone + "\r\n" +
						"END:VTIMEZONE\r\n" +
						"BEGIN:VEVENT\r\n" +
						"DTSTART:" + year + monthStr + dayStr + "T" + startHourStr + startMinStr + "00Z\r\n" + 
						"DTEND:" + endYear + endMonthStr + endDayStr + "T" + endHourStr + endMinStr + "00Z\r\n" +
						"DTSTAMP:" + todayYear + todayMonthStr + todayDayStr + "T" + currentHour + currentMin + currentSec + "Z\r\n" +
						"CLASS:PUBLIC\r\n" +
						"CREATED:" + todayYear + todayMonthStr + todayDayStr + "T" + currentHour + currentMin + currentSec + "Z\r\n" +
						"DESCRIPTION:" + description + "\r\n" +
						"COMMENT:" + comment + "\r\n" +
						"RESOURCES:" + resources + "\r\n" +
						"LAST-MODIFIED:" + todayYear + todayMonthStr + todayDayStr + "T" + currentHour + currentMin + currentSec + "Z\r\n" +
						"LOCATION:" + location + "\r\n" +
						"PRIORITY:"+ priority + "\r\n" +
						"SEQUENCE:0\r\n" +
						"STATUS:CONFIRMED\r\n" +
						"SUMMARY:" + name + "\r\n" +
						"TRANSP:OPAQUE\r\n" +
						"END:VEVENT\r\n" +
						"END:VCALENDAR\r\n";
				
				msGooglePW.print(fileContent);
				msGooglePW.close();
				
				return "MS Outlook and Google Calendar Compatible .ics File Contents:\n\n" + fileContent + "\n\n";
			} catch (IOException e) {
				return "Unable to write to MS Outlook/Google Calendar .ics event file.\n\n";
			} 
		} catch (IOException e) {
			return "MS Outlook/Google Calendar .ics event file not created.\n\n";
		}
	}
	
	/**
	 * createICal() method
	 * 
	 * Creates a new .ics event file in a file format compatible with Apple iCal, prints to the .ics file, returns
	 * an error message when an exception occurs or a file creation confirmation message. 
	 * 
	 * @param String		name				the event name
	 * @param int			startHourTime		the event time's starting hour
	 * @param int			startMinuteTime		the event time's starting minute
	 * @param String		startAMPM			the event time's starting AM/PM
	 * @param int			endHourTime			the event time's ending hour
	 * @param int			endMinuteTime		the event time's ending minute
	 * @param String		endAMPM				the event time's ending AM/PM
	 * @param int			month				the start month of the event
	 * @param int			day					the start day of the event
	 * @param int			year				the start year of the event
	 * @param int			endMonth			the end month of the event
	 * @param int			endDay				the end day of the event
	 * @param int			endYear				the end year of the event
	 * @param String		description			the event description
	 * @param String		location			the event location
	 * @param String		timezone			the event time zone
	 * @param String		comment				the event comment
	 * @param String		resources			the event resources
	 * @param String		priority			the priority of the event, no priority == 0, highest priority == 1, lowest priority == 9
	 * @param File			iCalDir				the path to the directory where all Apple iCal compatible .ics files are stored
	 * @param File			iCalFile			the path and filename of a Apple iCal compatible .ics file
	 * @param int			todayYear			today's year which is used to create a time stamp
	 * @param int			todayMonth			today's month which is used to create a time stamp
	 * @param int			todayDay			today's day which is used to create a time stamp
	 * @param String		currentHour			the current hour which is used to create a time stamp
	 * @param String		currentMin			the current minute which is used to create a time stamp
	 * @param String		currentSec			the current second which is used to create a time stamp
	 * 
	 * @return	The .ics file contents as a string or an error message
	 */
	public static String createICal(String name, int month, int day, int year, int endMonth, int endDay, int endYear, int startHourTime, 
									int startMinuteTime, String startAMPM, int endHourTime, int endMinuteTime, String endAMPM, 
									String description, String location, String timezone, String comment, String resources, int priority, 
									File iCalDir, File iCalFile, int todayYear, int todayMonth,	int todayDay, 
									String currentHour, String currentMin, String currentSec) {
		
		PrintWriter 	iCalPW 		= null; // writes to a text-output stream for Apple iCal compatible .ics files
		
		// Create the directory where Apple iCal .ics files will be stored, if it doesn't exist
		if (!iCalDir.exists()) {
			iCalDir.mkdir();
		}
		
		// Create the Applie iCal compatible .ics file and write to it
		try {
			iCalFile.createNewFile();
			try {
				iCalPW = new PrintWriter(iCalFile);
				
				String			monthStr		= Integer.toString(month); // a string representation of the Start Month
				String			dayStr			= Integer.toString(day); // a string representation of the Start Day
				String			endMonthStr		= Integer.toString(endMonth); // a string representation of the End Month
				String			endDayStr		= Integer.toString(endDay); // a string representation of the End Day
				String			todayMonthStr	= Integer.toString(todayMonth); // a string representation of today's month
				String			todayDayStr		= Integer.toString(todayDay); // a string representation of today's day
				String			startHourStr	= Integer.toString(startHourTime); // a string representation of the Start Time Hour
				String			startMinStr		= Integer.toString(startMinuteTime); // a string representation of the Start Time Minute
				String			endHourStr		= Integer.toString(endHourTime); // a string representation of the End Time Hour
				String			endMinStr		= Integer.toString(endMinuteTime); // a string representation of the End Time Minute
				String			fileContent		= ""; // the .ics file content
				
				if (monthStr.length() == 1) {
					monthStr = "0" + monthStr;
				}
				
				if (dayStr.length() == 1) {
					dayStr = "0" + dayStr;
				}
				
				if (endMonthStr.length() == 1) {
					endMonthStr = "0" + endMonthStr;
				}
				
				if (endDayStr.length() == 1) {
					endDayStr = "0" + endDayStr;
				}
				
				if (todayMonthStr.length() == 1) {
					todayMonthStr = "0" + todayMonthStr;
				}
				
				if (todayDayStr.length() == 1) {
					todayDayStr = "0" + todayDayStr;
				}
				
				if (startHourStr.length() == 1) {
					startHourStr = "0" + startHourStr;
				}
				
				if (startMinStr.length() == 1) {
					startMinStr = "0" + startMinStr;
				}
				
				if (endHourStr.length() == 1) {
					endHourStr = "0" + endHourStr;
				}
				
				if (endMinStr.length() == 1) {
					endMinStr = "0" + endMinStr;
				}
				
				fileContent = "BEGIN:VCALENDAR\r\n" +
							"METHOD:PUBLISH\r\n" +
							"VERSION:2.0\r\n" +
							"PRODID:-//Apple Inc.//iCal 4.0.4//EN\r\n" +
							"X-APPLE-CALENDAR-COLOR:#0252D4\r\n" +
							"X-WR-TIMEZONE:" + timezone + "\r\n" +
							"CALSCALE:GREGORIAN\r\n" +
							"BEGIN:VTIMEZONE\r\n" +
							"TZID:" + timezone + "\r\n" +
							"END:VTIMEZONE\r\n" +
							"BEGIN:VEVENT\r\n" +
							"CLASS:PUBLIC\r\n" +
							"CREATED:" + todayYear + todayMonthStr + todayDayStr + "T" + currentHour + currentMin + currentSec + "Z\r\n" +
							"DESCRIPTION:" + description + "\r\n" +
							"RESOURCES:" + resources + "\r\n" +
							"COMMENT:" + comment + "\r\n" +
							"DTEND;TZID=" + timezone + ":" + endYear + endMonthStr + endDayStr + "T" + startHourStr + startMinStr + "00\r\n" +
							"TRANSP:OPAQUE\r\n" +
							"SUMMARY:" + name + "\r\n" +
							"DTSTART;TZID=" + timezone + ":" + year + monthStr + dayStr + "T" + endHourStr + endMinStr + "00\r\n" +
							"DTSTAMP:" + todayYear + todayMonth + todayDay + "T" + currentHour + currentMin + currentSec + "Z\r\n" +
							"LOCATION:" + location + "\r\n" +
							"PRIORITY:"+ priority + "\r\n" +
							"SEQUENCE:4\r\n" +
							"END:VEVENT\r\n" +
							"END:VCALENDAR\r\n";
				
				iCalPW.print(fileContent);
			
				iCalPW.close();
				return "Apple iCal Compatible .ics File Contents:\n\n" + fileContent + "\n\n";
			} catch (IOException e) {
				return "Unable to write to iCal .ics event file.\n\n";
			} 
		} catch (IOException e) {
			return "iCal .ics event file not created.\n\n";
		}
	}
	
	/**
	 * replaceCommas() method
	 * 
	 * Replaces the commas found in an input string with "\\,".
	 * 
	 * @param String	input	the input string that will have its commas replaced by "\\,"
	 * @return	A string that has its commas replaced by "\\,"
	 */
	public static String replaceCommas(String input) {
		String temp = ""; // a temporary string
		
		for (int i = 0; i < input.length(); i++) {
			if (input.substring(i, i+1).equals(",")) {
				temp = temp + "\\,";
			}
			else {
				temp = temp + input.substring(i, i+1);
			}
		}
		input = temp;
		
		return input;
	}
	
	/**
	 * validateFilename() method
	 * 
	 * Validates whether or not the user inputed filename is in existence, if the filename exists, an incremented version number enclosed 
	 * in parentheses is concatenated to the end of the filename.
	 * 
	 * @param String	path		the path where the created .ics files are stored
	 * @param String	filename	the user inputed filename
	 * @return a new, valid filename that is not currently in existence
	 */
	public static String validateFilename(String path, String filename, int versionCount) {
		boolean fileExists		= (new File(path + filename + ".ics")).exists(); // a boolean that indicates whether or not the user inputed filename exists
		int fileLength			= filename.length(); // the length of the filename
		String versionStr		= "(" + (versionCount-1) + ")"; // the previous version number enclosed in parentheses
		int versionStrLength	= versionStr.length(); // length of the versionStr
		
		// If the user inputed filename exists concatenate the incremented version number enclosed in parentheses to the end of the filename
		if (fileExists == true) {
			versionCount++;
			if(filename.contains("(" + (versionCount-1) + ")")) {
				filename = filename.substring(0, (fileLength - versionStrLength));
			}
			filename = filename + "(" + versionCount + ")";
			filename = validateFilename(path, filename, versionCount);
		}
		
		return filename;
	}
}

